/**
 * libp2p集群示例
 * 
 * 这个示例展示了如何使用基于libp2p的集群提供者
 * 创建一个去中心化的Actor集群
 */

import { ActorSystem, Props } from '../src/actor';
import { Remote } from '../src/remote/remote';
import { Cluster } from '../src/cluster/cluster';
import { ClusterConfig } from '../src/cluster/clusterConfig';
import { Libp2pProvider } from '../src/cluster/providers/libp2pProvider';
import { LocalIdentityLookup } from '../src/cluster/providers/localIdentityLookup';
import { GrainBase, GrainRegistry } from '../src/cluster/grain';

// 延时函数
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

// ====== 定义计数器Grain接口 ======

interface ICounterGrain {
  // 获取当前值
  getValue(): Promise<number>;
  
  // 增加值
  increment(value: number): Promise<void>;
  
  // 减少值
  decrement(value: number): Promise<void>;
}

// ====== 实现计数器Actor ======

// 计数器Actor消息类型
type CounterActorMessage = 
  | { type: 'get-value' }
  | { type: 'increment', value: number }
  | { type: 'decrement', value: number };

// 计数器Actor
class CounterActor {
  // 计数器值
  private value: number = 0;
  
  constructor(private id: string) {}
  
  // 处理消息
  async receive(context: any): Promise<void> {
    const message = context.message as CounterActorMessage;
    
    switch (message.type) {
      case 'get-value':
        await this.handleGetValue(context);
        break;
        
      case 'increment':
        await this.handleIncrement(context, message.value);
        break;
        
      case 'decrement':
        await this.handleDecrement(context, message.value);
        break;
    }
  }
  
  // 处理获取值请求
  private async handleGetValue(context: any): Promise<void> {
    await context.respond(this.value);
  }
  
  // 处理增加值请求
  private async handleIncrement(context: any, value: number): Promise<void> {
    this.value += value;
    await context.respond({ success: true });
  }
  
  // 处理减少值请求
  private async handleDecrement(context: any, value: number): Promise<void> {
    this.value -= value;
    await context.respond({ success: true });
  }
}

// ====== 实现计数器Grain ======

// 计数器Grain实现
class CounterGrain extends GrainBase implements ICounterGrain {
  constructor(cluster: Cluster, counterId: string) {
    super(cluster, 'counter', counterId);
  }
  
  // 获取当前值
  async getValue(): Promise<number> {
    // 激活Grain
    const pid = await this.activate();
    if (!pid) {
      throw new Error('无法激活CounterGrain');
    }
    
    // 调用Actor方法
    const actorSystem = this.cluster.getActorSystem();
    return actorSystem.root.requestAs<number>(pid, { type: 'get-value' });
  }
  
  // 增加值
  async increment(value: number): Promise<void> {
    // 激活Grain
    const pid = await this.activate();
    if (!pid) {
      throw new Error('无法激活CounterGrain');
    }
    
    // 调用Actor方法
    const actorSystem = this.cluster.getActorSystem();
    const response = await actorSystem.root.requestAs<{ success: boolean }>(
      pid, 
      { type: 'increment', value }
    );
    
    if (!response.success) {
      throw new Error('增加值失败');
    }
  }
  
  // 减少值
  async decrement(value: number): Promise<void> {
    // 激活Grain
    const pid = await this.activate();
    if (!pid) {
      throw new Error('无法激活CounterGrain');
    }
    
    // 调用Actor方法
    const actorSystem = this.cluster.getActorSystem();
    const response = await actorSystem.root.requestAs<{ success: boolean }>(
      pid, 
      { type: 'decrement', value }
    );
    
    if (!response.success) {
      throw new Error('减少值失败');
    }
  }
}

// ====== 计数器Grain工厂 ======

class CounterGrainFactory {
  constructor(private cluster: Cluster) {}
  
  // 获取计数器Grain
  get(counterId: string): CounterGrain {
    return new CounterGrain(this.cluster, counterId);
  }
}

// ====== 主函数 ======

async function main() {
  try {
    console.log('启动libp2p集群示例...');
    
    // 创建Actor系统
    const system = new ActorSystem();
    
    // 配置远程通信
    const remote = new Remote(system, {
      host: 'localhost',
      port: 12001
    });
    
    // 启动远程通信系统
    await remote.start();
    console.log('远程通信系统已启动');
    
    // 创建集群配置
    const clusterConfig: ClusterConfig = {
      clusterName: 'libp2p-cluster',
      nodeAddress: 'localhost:12001',
      hostname: 'localhost',
      port: 12001,
      providerType: 'libp2p',
      providerConfig: {},
      reconnectInterval: 1000,
      heartbeatInterval: 1000,
      enableVirtualNodes: false,
      virtualNodeCount: 10
    };
    
    // 创建libp2p集群提供者
    const provider = new Libp2pProvider({
      listenAddrs: ['/ip4/0.0.0.0/tcp/0'],
      enableMDNS: true,
      enableDHT: true,
      enableGossip: true,
      heartbeatInterval: 1000,
      memberTTL: 10000,
      leaderElectionInterval: 5000
    });
    
    // 创建本地身份查找服务
    const identityLookup = new LocalIdentityLookup({
      enableCache: true,
      cacheExpiration: 10000
    });
    
    // 创建集群
    const cluster = new Cluster(system, remote, clusterConfig, provider, identityLookup);
    
    // 初始化集群
    await cluster.init();
    console.log('集群已初始化');
    
    // 注册计数器Grain
    const registry = GrainRegistry.getInstance();
    
    // 注册Grain种类
    registry.registerGrain('counter', (identity) => {
      return Props.fromProducer(() => new CounterActor(identity));
    });
    
    // 启动集群
    await cluster.start();
    console.log('集群已启动');
    
    // 等待集群稳定
    await delay(1000);
    
    // 创建计数器Grain工厂
    const counterGrainFactory = new CounterGrainFactory(cluster);
    
    // 创建不同的计数器Grain
    const counter1 = counterGrainFactory.get('counter-1');
    const counter2 = counterGrainFactory.get('counter-2');
    
    // 使用counter1
    console.log('获取计数器1的值...');
    const value1 = await counter1.getValue();
    console.log('计数器1的值:', value1);
    
    // 增加counter1的值
    console.log('增加计数器1的值...');
    await counter1.increment(10);
    
    // 获取更新后的counter1值
    console.log('获取更新后的计数器1值...');
    const updatedValue1 = await counter1.getValue();
    console.log('更新后的计数器1值:', updatedValue1);
    
    // 使用counter2
    console.log('获取计数器2的值...');
    const value2 = await counter2.getValue();
    console.log('计数器2的值:', value2);
    
    // 增加counter2的值
    console.log('增加计数器2的值...');
    await counter2.increment(5);
    
    // 减少counter2的值
    console.log('减少计数器2的值...');
    await counter2.decrement(2);
    
    // 获取更新后的counter2值
    console.log('获取更新后的计数器2值...');
    const updatedValue2 = await counter2.getValue();
    console.log('更新后的计数器2值:', updatedValue2);
    
    // 关闭Grain
    await counter1.shutdown();
    await counter2.shutdown();
    
    // 等待一段时间让日志输出
    await delay(1000);
    
    // 关闭集群
    console.log('关闭集群...');
    await cluster.shutdown();
    
    // 关闭远程系统
    await remote.shutdown();
    
    // 结束示例
    console.log('libp2p集群示例已完成');
  } catch (error) {
    console.error('libp2p集群示例出错:', error);
  }
}

// 运行主函数
main().catch(console.error); 